package org.nobject.common.lang;

import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.nobject.common.bean.BeanUtils;

/**
 * List工具类
 * extractXXX:抽取类方法
 * @author bianrongjun
 * @version 1.0
 */
public class ListUtils {
	
	/** 
	 * 排序
	 * @param list
	 * @param key
	 * @param asc
	 * @return
	 */
	public static void sort(List list,final String key,final boolean asc){
		
		Comparator sort=new Comparator() {
			public int compare(Object o1, Object o2) {
				boolean isMap =o1 instanceof Map;
				Object v1 = isMap?((Map)o1).get(key):BeanUtils.getProperty(o1, key);
				Object v2 = isMap?((Map)o2).get(key):BeanUtils.getProperty(o2, key);
				if(asc){
					return ObjectUtils.compare(v1,v2);
				}else{
					return ObjectUtils.compare(v2,v1);
				}
				
			}
		};
		
		Collections.sort(list,sort);
		
	}
	
	/** 
	 * 批量添加
	 * @param list
	 * @param os
	 */
	public static List add(List list,Object[] os){
		for(Object o:os){
			list.add(o);
		}
		return list;
	}
	
	/** 
	 * 批量添加
	 * @param list
	 * @param os
	 * @param idx
	 */
	public static List add(List list,Object[] os,int idx){
		for(Object o:os){
			list.add(idx,o);
			idx++;
		}
		return list;
	}
//	
//	public static void main(String[] args) {
//		List l=new LinkedList();
//		l.add("a");
//		l.add("d");
//		l.add("e");
//		List l2=new LinkedList();
//		l2.add("b");
//		l2.add("c");
//		add(l, l2.toArray(), 1);
//		System.out.println(l);
//	}
	
	/** 
	 * 提取List中对象的属性值,添加到新的List
	 * @param list 原List
	 * @param key 键值
	 */
	public static List extract(List list,String key){
		return extract(list, key, false, false);
	}
	
	/**
	 * 提取List中对象的属性值,添加到新的List
	 * 取值方式:如果原List对象是Map类型靠键值取值，否则用BeanUtils的getProperty方法取值
	 * 	EXP:
	 * 	[{'a':'A1'},{'a':'A2'}]
	 * 	=>
	 * 	["A1","A2"]
	 * @param list 原List
	 * @param key 键值
	 * @param ignoreEmpty 是否为空
	 * @param ignoreExsist 是否存在
	 */
	public static List extract(List list,String key,boolean ignoreEmpty,boolean ignoreExsist){
		List nl=new LinkedList();
		for (int i = 0;i<list.size(); i++) {
			Object o = list.get(i);
			Object v=null;
			if(o instanceof Map){
				v=((Map)o).get(key);
			}else{
				try {
					v=BeanUtils.getProperty(o, key);
				} catch (Exception e){
					continue;
				}
			}
			
			//C:是否为空
			if(ignoreEmpty&&ObjectUtils.isEpmty((String)v)){
				continue;
			}
			
			//C:是否存在
			if(ignoreExsist&&nl.contains(v)){
				continue;
			}
			
			nl.add(v);
			
		}
		return nl;
	}
	
	/** 
	 * 提取List中对象的键值1对应值作为键，将键值2对应值作为值(键值2为空时将整个Map(或对象)作为数值),添加到新的Map,返回Map
	 * 取值方式:同{@link #addAll(List, Object[])}
	 * EXP:
	 * 	[{'a':'A1','b':'B1'},{'a':'A2','b':'B2'}]
	 * 	=>
	 * 	{"A1":"B1","A2":"B2"}
	 * @param list 原List
	 * @param keyKey 键值1
	 * @param keyValue 键值2
	 */
	public static Map extract2Map(List list,String keyKey,String keyValue){
		Map m=new LinkedHashMap();
		if(list==null) return m;
		for (int i = 0,il=list.size(); i <il; i++) {
			Object o = list.get(i);
			if(o instanceof Map){
				Map lm=(Map)o;
				m.put(lm.get(keyKey), keyValue==null?lm:lm.get(keyValue));
			}else{
				try {
					m.put(BeanUtils.getProperty(o, keyKey),  keyValue==null?o:BeanUtils.getProperty(o, keyValue));
				} catch (Exception e){
					continue;
				}
			}
		}
		return m;
	}
	
	/** 
	 * 提取List中对象的键值1对应值作为键，整个Map(或对象),添加到新的Map,返回Map
	 * @param list 原List
	 * @param key1 键值
	 */
	public static Map extract2Map(List list,String key1){
		return extract2Map(list, key1, null);
	}
	
	/** 
	 * 提取List中对象的键值1对应值作为键，创建一个List保存键值2对应的值或整个Map(或对象),返回Map
	 * EXP:
	 * 	[{'a':'A1','b':'B1'},{'a':'A1','b':'B2'},{'a':'A2','b':'B3'}]
	 * 	=>
	 * 	{"A1":["B1","B2"],"A2":["B3"]}
	 * @param list 原List
	 * @param key1 键值1
	 * @param key2 键值2
	 * @return
	 */
	public static Map extract2MapList(List list,String key1,String key2){
		Map<Object,List> m=new LinkedHashMap();
		if(list==null) return m;
		for (int i = 0,il=list.size(); i <il; i++) {
			Object object = list.get(i);
			if(object instanceof Map){
				Map lm=(Map)object;
				List l;
				Object key=lm.get(key1);
				if(!m.containsKey(key)){
					m.put(key,new LinkedList());
				}
				l=m.get(key);
				l.add(key2==null?lm:lm.get(key2));
			}else{
				try {
					Object key=BeanUtils.getProperty(object, key1);
					List l;
					if(!m.containsKey(key)){
						m.put(key,new LinkedList());
					}
					l=m.get(key);
					l.add(key2==null?object:BeanUtils.getProperty(object, key2));
				} catch (Exception e){
					continue;
				}
			}
		}
		return m;
	}
	
	/** 
	 * 提取List中对象的键值对应值作为键，创建一个List保存整个Map(或对象),返回Map
	 * @param list 原List
	 * @param key 键值
	 */
	public static Map extract2MapList(List list,String key){
		return extract2MapList(list, key, null);
	}
	
	/** 
	 * 根据某个键值，叠加List内的元素
	 * @param srclist
	 * @param overlist
	 * @param overKey
	 */
	public static List overlay(List<Map> srclist,List<Map> overlist,String key) {
		for(Map m:srclist){
			Object sV=m.get(key);
			Map subM=(Map)CollectionUtils.fetch(overlist, key, sV);
			if(subM==null) continue;
			MapUtils.copy(m, subM, true);
		}
		return srclist;
	}
	
	/**
	 * 提取List中对象的键值对应值,生成新的数组
	 * @param list 原List
	 * @param key 键值
	 */
	public static Object [] extract2Array(List list,String key){
		return extract2Array(list, key, Object.class);
	}
	
	/** 
	 * 提取List中对象的键值对应值,生成新的数组
	 * @param list 原List
	 * @param key 属性
	 * @param arrayClass 数组类型
	 */
	public static Object [] extract2Array(List list,String key,Class arrayClass){
		return ArrayUtils.toArray(extract(list, key,false,false), arrayClass);
	}
	
	/** 
	 * extract2Array0
	 * @param list
	 * @param key
	 * @param arrayClass
	 * @return
	 */
	public static Object extract2Array0(List list,String key,Class arrayClass){
		return ArrayUtils.toArray0(extract(list, key,false,false), arrayClass);
	}
	
	/** 
	 * 提取List中对象的键值对应值,生成新的数组
	 * @param list 原List
	 * @param key 属性
	 * @param ignoreEmpty 忽略空值
	 * @param ignoreExsist 忽略已存在
	 * @param arrayClass 数组类型
	 */
	public static Object [] extract2Array(List list,String key,boolean ignoreEmpty,boolean ignoreExsist,Class arrayClass){
		return ArrayUtils.toArray(extract(list, key,ignoreEmpty,ignoreExsist), arrayClass);
	}
	
	/**
	 * 指定元素前移
	 * @param list 原List
	 * @param srcIdx 索引
	 */
	public static void moveUp(List list,int srcIdx){
		_moveUp(list,srcIdx,srcIdx-1);
	}
	
	/**
	 * 指定元素后移
	 * @param list 原List
	 * @param srcIdx 索引
	 */
	public static void moveDown(List list,int srcIdx){
		_moveUp(list,srcIdx,srcIdx+1);
	}
	
	/**
	 * 移动元素
	 * @param 原List
	 * @param srcIdx 原索引
	 * @param destIdx 目标索引
	 */
	private static void _moveUp(List list,int srcIdx,int destIdx){
		if(list==null) return;
		int l=list.size();
		if(srcIdx>l-1||destIdx>l-1||srcIdx<0||destIdx<0) return;
		Object srcObj=list.get(srcIdx);
		Object destObj=list.get(destIdx);
		list.set(srcIdx, destObj);
		list.set(destIdx, srcObj);
		return;
	}
	
	/**
	 * 数组转换为List
	 * @param os 数组
	 */
	public static List toList(Object[] os){
		return toList0(os);
	}
	
	/**
	 * 数组转换为List
	 * 支持基础数据
	 * @param os
	 */
	public static List toList0(Object os){
		List l=new LinkedList();
		int size=Array.getLength(os);
		for (int i = 0; i < size; i++) {
			l.add(Array.get(os, i));
		}
		return l;
	}
	
	/** 
	 * 转换为List
	 * @param collection 原Collection
	 */
	public static List toList(Collection collection){
		List l=new LinkedList();
		for (Iterator iterator = collection.iterator(); iterator.hasNext();) {
			l.add(iterator.next());
		}
		return l;
	}
	
	/** 
	 * 字符串转换为List
	 * @param str 字符串
	 * @param spliter 分隔符
	 * @see #toList(Object[])
	 */
	public static List toList(String str,String spliter){
		return toList(str.split(spliter));
	}
	
	/** 
	 * 转化成指定类型的链表
	 * @param l 数据
	 * @param c 待转类型
	 */
	public static List format(List l,Class c){
		List nl=new LinkedList();
		try {
			for (int i = 0; i < l.size(); i++) {
				nl.add(ObjectUtils.toObject(l.get(i), c));
			}
			return nl;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	
//	public static void main(String[] args) throws Exception{
//		List l=JSONUtils.toList("[{'a':'A1','b':'B1'},{'a':'A1','b':'B2'},{'a':'A2','b':'B3'}]");
//		System.out.println(JSONUtils.toString(extract2MapList(l, "a", "b")));
//	}
	
}
